﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;


namespace RStudio.Elevator
{
    /// <summary>
    /// 电梯|呼叫队列
    /// </summary>
    public class ElevatorQueue
    {
        public ElevatorQueue(ElevatorComponent elevatorComponent)
        {
            this.Component = elevatorComponent;

            this._QueueUpper = new Queue<DataFloor>();
            this._QueueDown = new Queue<DataFloor>();
        }

        /// <summary>
        /// 关联组
        /// </summary>
        public ElevatorComponent Component { get; private set; }

        /// <summary>
        /// 上行队列
        /// </summary>
        private readonly Queue<DataFloor> _QueueUpper;

        /// <summary>
        /// 下行队列
        /// </summary>
        private readonly Queue<DataFloor> _QueueDown;

        /// <summary>
        /// 事件|队列更新
        /// </summary>
        public event Action<QueueEvent> OnQueueUpdated;

        /// <summary>
        /// 任务队列类型
        /// </summary>
        public ElevatorQueueType Current { get; private set; }


        /// <summary>
        /// 
        /// </summary>
        public void SendRequest(DataFloorRequest request)
        {
            DataFloor match = this.Component.Plan.Get(request.FloorNo);
            if (match == null)
            {
                Debug.LogWarning($"<color=green><b>[ElevatorQueue]</b></color> " +
                    $"{this.Component.Plan.Name} | " +
                    $"楼层 {request.FloorNo} 不可用");
                return;
            }



            ElevatorDriven driven = this.Component.Driven;
            if (driven.StatusRunning == ElevatorRunningType.IsUpper)
            {
                if (!IsGreaterThanCurrent(match.FloorNo))
                {
                    this.SendToDown(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                if (IsClamp(match.FloorNo))
                {
                    this.SendToDown(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                this.SendToUpper(match, request.IsSelected);
                this.Notice();
                return;
            }

            if (driven.StatusRunning == ElevatorRunningType.IsDown)
            {
                if (!IsLessThanCurrent(match.FloorNo))
                {
                    this.SendToUpper(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                if (IsClamp(match.FloorNo))
                {
                    this.SendToUpper(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                this.SendToDown(match, request.IsSelected);
                this.Notice();
                return;
            }

            if (driven.StatusRunning == ElevatorRunningType.UnKnown)
            {
                if (IsLessThanCurrentVer(match.FloorVertical))
                {
                    this.SendToDown(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                if (IsGreaterThanCurrentVer(match.FloorVertical))
                {
                    this.SendToUpper(match, request.IsSelected);
                    this.Notice();
                    return;
                }

                Debug.LogWarning($"<color=green><b>[ElevatorQueue]</b></color> 楼层值与目标值一致");
                this.OnQueueUpdated?.Invoke(new(match, ElevatorQueueType.UnKnown));
                return;
            }

            Debug.Log($"<color=green>[ElevatorQueue]</color> {driven.StatusRunning}");
        }

        /// <summary>
        /// 
        /// </summary>
        public void Notice()
        {
            if (!HasMission()) return;

            if (Current == ElevatorQueueType.isQueueUp)
            {
                if (this._QueueUpper.Count != 0)
                {
                    this.OnQueueUpdated?.Invoke(new(GetNext(ElevatorQueueType.isQueueUp), ElevatorQueueType.isQueueUp));
                    return;
                }

                Current = ElevatorQueueType.isQueueDown;
                this.Notice();
                return;
            }

            if (Current == ElevatorQueueType.isQueueDown)
            {
                if (this._QueueDown.Count != 0)
                {
                    this.OnQueueUpdated?.Invoke(
                        new(GetNext(ElevatorQueueType.isQueueDown), 
                        ElevatorQueueType.isQueueDown));
                    return;
                }

                Current = ElevatorQueueType.isQueueUp;
                this.Notice();
                return;
            }

            if (Current == ElevatorQueueType.UnKnown)
            {
                // 优先上行
                this.Current = ElevatorQueueType.isQueueUp;
                this.Notice();
            }
        }




        /// <summary>
        /// 查询|下一目标层数据
        /// </summary>
        public DataFloor GetNext(ElevatorQueueType queueType)
        {
            return queueType switch
            {
                ElevatorQueueType.UnKnown => null,
                ElevatorQueueType.isQueueUp => this._QueueUpper.Peek(),
                ElevatorQueueType.isQueueDown => this._QueueDown.Peek(),
                _ => null,
            };
        }

        /// <summary>
        /// 抽取|数据
        /// </summary>
        public DataFloor Remove(ElevatorQueueType queueType)
        {
            return queueType switch
            {
                ElevatorQueueType.UnKnown => null,
                ElevatorQueueType.isQueueUp => this._QueueUpper.Dequeue(),
                ElevatorQueueType.isQueueDown => this._QueueDown.Dequeue(),
                _ => null,
            };
        }

        /// <summary>
        /// 查询|是否有队列任务
        /// </summary>
        public bool HasMission()
        {
            return this._QueueDown.Count > 0 || this._QueueUpper.Count > 0;
        }



        /// <summary>
        /// 管理上行队列
        /// </summary>
        private void SendToUpper(DataFloor dataFloor, bool isSelected)
        {
            HashSet<DataFloor> hashDatas = this._QueueUpper.ToHashSet();

            if (isSelected)
            {
                hashDatas.Add(dataFloor);
            }
            else
            {
                hashDatas.Remove(dataFloor);
            }

            var datas = hashDatas.OrderBy(a => a.FloorNo).ToList();

            this._QueueUpper.Clear();

            foreach (var item in datas)
            {
                this._QueueUpper.Enqueue(item);
            }
        }

        /// <summary>
        /// 管理下行队列
        /// </summary>
        private void SendToDown(DataFloor dataFloor, bool isSelected)
        {
            HashSet<DataFloor> hashDatas = this._QueueDown.ToHashSet();

            if (isSelected)
            {
                hashDatas.Add(dataFloor);
            }
            else
            {
                hashDatas.Remove(dataFloor);
            }

            var datas = hashDatas.OrderByDescending(a => a.FloorNo).ToList();
            this._QueueDown.Clear();

            foreach (var item in datas)
            {
                this._QueueDown.Enqueue(item);
            }
        }




        private bool IsClamp(int number)
        {
            return Mathf.Abs(this.Component.Driven.CurrentFloorNo - number) <= 2;
        }
        private bool IsGreaterThanCurrent(int number)
        {
            return this.Component.Driven.CurrentFloorNo < number;
        }
        private bool IsLessThanCurrent(int number)
        {
            return this.Component.Driven.CurrentFloorNo > number;
        }
        private bool IsGreaterThanCurrentVer(float vertical)
        {
            return this.Component.transform.position.y < vertical;
        }
        private bool IsLessThanCurrentVer(float vertical)
        {
            return this.Component.transform.position.y > vertical;
        }
    }
}
